/*	Interactive Gravitational Simulator
	Project: IGS Core
	File: Body.cpp
	Author: Mike Bantegui <mbante2@gmail.com>, Hofstra University 
	Copyright (C) 2012 - 2013 Mike Bantegui

	This file is part of the IGS software package for simulating
	the N-Body problem in real-time. This was developed as part
	of a departmental honors thesis project at Hofstra University
	in the Spring 2012 semester.

	IGS is free software; you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation; either version 2 of the License, or
	(at your option) any later version.

	IGS is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public License
	along with this program; if not, write to the Free Software
	Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
*/

#include "Body.h"
#include <iostream>

namespace IGS
{

// Default constructs a Body
Body::Body() : Graviton(), CollisionTimescaleSq(1E12), NextTime(1E12)
{
}

// Constructs a Body with the specified mass, position and velocity
Body::Body(const double mass, const Vector &position, const Vector &velocity)
	: Graviton(mass, position, velocity), CollisionTimescaleSq(1E12), NextTime(1E12)
{
}

// Destruct the Body
Body::~Body()
{
}

// Body does not participate as a ViewNode
ViewNode *Body::AsReadOnly() const
{
	return NULL;
}

// Choose minimum of possible collision timescales
void Body::CheckTimescale(const double timescaleSquared)
{
	CollisionTimescaleSq = std::min(CollisionTimescaleSq, timescaleSquared);
}

// Compute the pairwise gravity between this Body and the other Body
void Body::Pairwise(Body &other, const double softening)
{
	const Vector &dr = other.Position - this->Position;
	const double &r2 = Dot(dr, dr);

	IGS::Pairwise(*this, other, softening, dr, r2);
}

// Computes the force of gravity due to the other Body on this Body
void Body::Direct(Body &other, const double softening) const
{
	const Vector &dr = this->Position - other.Position;
	const double &r2 = Dot(dr, dr);

	IGS::Direct(other, *this, softening, dr, r2);
}

// Body does not contribute to multipole potential
// The potential for a body is exact
double Body::MultipolePotential(const Vector &dr, const double r1,
	const double r2) const
{
	return 0;
}

// Body does not participate in the multipole expansion
void Body::AddMultipole(Node &branch) const
{
}

// Ends a step of integration
void Body::EndStep()
{
	End = Start;
	Start = *this;
}

// Writes the body to the output stream
std::ostream &operator<<(std::ostream &os, const Body &body)
{
	os << body.Mass << " " << body.Position << " " << body.Velocity;
	os << body.Time;
	return os;
}

// Reads a body in from the input stream
std::istream &operator>>(std::istream &is, Body &body)
{
	is >> body.Mass >> body.Position >> body.Velocity >> body.Time;
	return is;
}

}